package dk.aiszone.lang.sql;

import java.util.Collection;
import java.util.Iterator;

import dk.aiszone.lang.sql.interfaces.SQLConstraint;
import dk.aiszone.lang.sql.interfaces.SQLObject;

/**
 * Representation of the in (in()) operator in SQL.
 * 
 * @author Ais
 */
public class SQLIn extends AbstractSQLObject implements SQLConstraint {

    private SQLAssignableField assignableField;

    /**
     * Constructor for the <code>SQLIn</code> object.
     * 
     * @param field
     *            The field to match
     */
    public SQLIn(SQLAssignableField field) {
        this.assignableField = field;
    }

    @Override
    public SQLAssignableField getAssignableField() {
        return assignableField;
    }

    @Override
    public SQLResult prepareSQL(SQLResult sql) {
        if (!assignableField.isAssigned()) {
            return sql.append(this);
        }

        sql.append(assignableField.getField());

        Object value = assignableField.getValue();
        if (value != null && SQLObject.class.isAssignableFrom(value.getClass())) {
            sql.append(" IN (");
            sql = ((SQLObject)value).prepareSQL(sql);
            return sql.append(")");
        }
        return sql.append(toSQL(value));
    }

    @Override
    public String toPreparedStatement() {
        StringBuilder sb = new StringBuilder();
        sb.append(assignableField.getField());
        return sb.append(toSQL(assignableField.getValue())).toString();
    }

    @Override
    public String toSQL() {
        StringBuilder sb = new StringBuilder();
        sb.append(assignableField.getField());
        return sb.append(toSQL(assignableField.getValue())).toString();
    }

    private String format(Object value) {
        if (String.class.equals(value.getClass())) {
            return "'" + (String)value + "'";
        } else if (Boolean.class.equals(value.getClass()) || Number.class.isAssignableFrom(value.getClass())) {
            return value.toString();
        }
        return value.toString();
    }

    private String toSQL(Object value) {
        if (value instanceof Collection) {
            StringBuilder sb = new StringBuilder();
            sb.append(" IN (");

            Collection<?> values = (Collection<?>)value;
            for (Iterator<? extends Object> iterator = values.iterator(); iterator.hasNext();) {
                sb.append(format(iterator.next()));
                if (iterator.hasNext()) {
                    sb.append(", ");
                }
            }
            return sb.toString();
        }
        return " IN (" + format(value) + ")";
    }
}